// Copyright (c)  YISH. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Text;
using NSQL.Sharpen;

namespace NSQL.DateFormats
{
    [SuppressMessage("ReSharper", "InconsistentNaming")]
    [CLSCompliant(false)]
    public class StandardDateFormatter : IDatetimeFormatter
    {
        public static readonly IDatetimeFormatter Instance = new StandardDateFormatter();

        public virtual string yy { get; } = nameof(yy);
        public virtual string YY { get; } = nameof(YY);
        public virtual string yyyy { get; } = nameof(yyyy);
        public virtual string YYYY { get; } = nameof(YYYY);
        
        public virtual string mm { get; } = nameof(mm);
        public virtual string MM { get; } = nameof(MM);
        
        public virtual string MON { get; } = nameof(MON);
        public virtual string Mon { get; } = nameof(Mon);
        public virtual string mon { get; } = nameof(mon);
        
        public virtual string MONTH { get; } = nameof(MONTH);
        public virtual string Month { get; } = nameof(Month);
        public virtual string month { get; } = nameof(month);

        public virtual string dd { get; } = nameof(dd);
        public virtual string DD { get; } = nameof(DD);
        public virtual string DY { get; } = nameof(DY);
        public virtual string Dy { get; } = nameof(Dy);
        public virtual string dy { get; } = nameof(dy);
        
        public virtual string DAY { get; } = nameof(DAY);
        public virtual string Day { get; } = nameof(Day);
        public virtual string day { get; } = nameof(day);
        
        
        
        public virtual string hh { get; } = nameof(hh);
        public virtual string HH { get; } = nameof(HH);
        public virtual string hh12 { get; } = nameof(hh12);
        public virtual string HH12 { get; } = nameof(HH12);
        
        public virtual string hh24 { get; } = nameof(hh24);
        public virtual string HH24 { get; } = nameof(HH24);


        public virtual string mi { get; } = nameof(mi);
        public virtual string MI { get; } = nameof(MI);
        
        
        public virtual string ss { get; } = nameof(ss);
        public virtual string SS { get; } = nameof(SS);

        private IReadOnlyList<PropertyInfo> _properties;

        private IEnumerable<PropertyInfo> GetProperties() =>
            _properties ?? (_properties = GetType().GetProperties()
                .OrderByDescending(o => o.Name.Length).ToList());

        protected StandardDateFormatter()
        {
        }

        public string Format(string format)
        {
            if (string.IsNullOrWhiteSpace(format)) return format;
            
            var lst = new List<(int index, PropertyInfo property)>();
            foreach (var property in GetProperties())
            {
                var index = format.IndexOf(property.Name, StringComparison.Ordinal);
                if (index <= -1) continue;
                
                if (lst.All(o =>  !o.property.Name.StartsWith(property.Name)))
                {
                    lst.Add((index, property));
                }
            }

            if (lst.Count <= 0) return format;
            
            lst.Sort(Comparer);


            var builder = new StringBuilder();
            var from = 0;
            foreach (var tuple in lst)
            {
                var length = tuple.index - from;
                if (length > 0)
                {
                    builder.Append(format.Substring(from, length));
                }
                builder.Append(tuple.property.GetValue(this));
                from = tuple.index + tuple.property.Name.Length;
            }

            var len =format.Length - from;
            if (len > 0)
            {
                builder.Append(format.Substring(from, len));
            }
            
            return builder.ToString();
        }

        private static readonly CustomComparer<(int index, PropertyInfo property)> Comparer =
            new CustomComparer<(int index, PropertyInfo property)>((x, y) => x.index - y.index);
    }
}